package com.miyu.book.service.bookMagic.impl;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.miyu.book.dao.bookMagic.BookMagicDao;
import com.miyu.book.pojo.BookRuleSet;
import com.miyu.book.service.bookMagic.BookMagicService;
import com.miyu.book.utils.bookUtils.BookCommutils;
import com.miyu.book.utils.bookUtils.JXPageRuleThread;
import com.miyu.book.utils.bookUtils.saveRedisThead;
import com.miyu.book.utils.ehcache.EhcacheUtil;
import lombok.SneakyThrows;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.RequestMapping;

import javax.annotation.Resource;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

/**
 * 魔法书服务impl
 *
 * @author longm
 * @date 2022/09/09
 */
@Service
public class BookMagicServiceImpl implements BookMagicService {

    @Resource
    private BookMagicDao dao;
    @Override
    public List<BookRuleSet> queryRuleSet(JSONObject param) {
        return dao.findAll();
    }

    @Override
    public JSONArray searchBook(JSONObject param) {

        List<String> num = new ArrayList<>();
        num.add("bookSearch");
        //取出规则
        StringBuffer sql = new StringBuffer();
        sql.append("select rule_id ruleId ,rule_name ruleName ,root_source rootSource,root_search rootSearch,root_type rootType,rule_book_list ruleBookList,");
        sql.append(" rule_chapter_list ruleChapterList, rule_set ruleSet ");
        sql.append(" from book_rule_set where is_stop = '0' ");
        if(param.containsKey("ruleId"))
            sql.append(" and rule_id = '").append(param.getString("ruleId")).append("'");

        JSONArray ds = dao.queryJSONArrayBySql(sql.toString());

        JSONObject req = new JSONObject();
        JSONObject bs=null;
        String id = "";
        if (ds.size()>0){
            for (int i = 0; i < ds.size(); i++) {
                JSONObject jo = ds.getJSONObject(i);
                JSONObject reset = JSONObject.parseObject(jo.getString("ruleSet"));
                param.put("ruleId",jo.getString("ruleId"));
                List<String> set = new ArrayList<>();
                if(param.containsKey("search"))
                    req.put("url",jo.getString("rootSearch")+param.getString("search"));
                set.add("bookSearch");
                JSONObject cond = new JSONObject();
                cond.put("key",jo.getString("ruleId"));
                cond.put("keyName",jo.getString("ruleName"));
                cond.put("num",set);
                req.put("ruleSet",reset);
                req.put("cond",cond);
                req.put("thread",1);
                req.put("param",param);//附加参数
                jxRulePage(req);
                id=jo.getString("ruleId");
                bs = (JSONObject) EhcacheUtil.getInstance().get("bookEhcache",jo.getString("ruleId"));
            }
        }
        JSONArray rs =  bs.getJSONArray("bookSearch");
        EhcacheUtil.getInstance().remove("bookEhcache",id);
        return rs;
    }

    /**
     * 查询数据章节以及数据信息
     * @param param
     * @return
     */
    @Override
    public JSONObject queryDetailBookList(JSONObject param) {
        JSONObject bs= new JSONObject();
        JSONObject br = dao.queryJSONObjectBySql(BookCommutils.bookRuleStr(param));
        String bookId = BookCommutils.MD5(param.getString("bookUrl"));
        param.put("type","bookChapterList");
        JSONObject req = new JSONObject();
        JSONObject reset = JSONObject.parseObject(br.getString("ruleSet"));
        String ruleId = param.getString("ruleId") ;
        List<String> set = new ArrayList<>();
        set.add("bookChapterList");
        JSONObject cond = new JSONObject();
        cond.put("key",bookId);
        cond.put("num",set);
        req.put("ruleSet",reset);
        req.put("cond",cond);
        req.put("thread",1);
        req.put("param",param);//附加参数
        req.put("url",param.getString("bookUrl"));
        jxRulePage(req);
        bs = (JSONObject) EhcacheUtil.getInstance().get("bookEhcache",bookId);
        JSONObject bf = bs.getJSONObject("chapterInfo");
        JSONArray ch = new JSONArray();

        for (Map.Entry entry : bf.entrySet()) {
            ch.add(entry.getValue());
        }
        ch.sort(Comparator.comparing(obj -> ((JSONObject) obj).getInteger("num")));
        bs.put("chapterInfo",ch);

        //调用多线程处理 保存点击查询的数据 数据明细以及章节 后对章节进行内容更新 返回筛选知道所有章节更新完毕
/*        ExecutorService exec = Executors.newFixedThreadPool(1);// 线程数
        exec.submit(new saveThead(br,bs));*/
        return bs;
    }

    /**
     * 章节阅读
     * 必须包含
     * Ruleid 来源规则  bookId 书籍Id  chapterUrl  章节ID
     * key值重新定义 需要传入key值取值  不再解析中取值
     * 鉴于上一章 下一章只改变了 当前连接的url 其余信息相同所以需要根据当前url 重新生成param 参数
     * @param param
     * @return
     */
    @Override
    public JSONObject readBook(JSONObject param) {
        if (param.containsKey("type")){
            param.put("chapterId", BookCommutils.MD5(param.getString("chapterUrl")));
            if(param.getString("type").equals("up")){
                //下页 搜索页进来的没有num属性 可不赋次属性
                if (param.containsKey("num"))
                    param.put("num",param.getInteger("num")-1);
            }else{
                //下页 搜索页进来的没有num属性 可不赋次属性
                if (param.containsKey("num"))
                    param.put("num",param.getInteger("num")+1);
            }
        }
        String chapterId = "";
        if(param.containsKey("chapterId"))
            chapterId = param.getString("chapterId");
        else
            chapterId = BookCommutils.MD5(param.getString("chapterUrl"));
        //先判断数据库中或缓存中是否含有此文本内容 如果不含者从网上下载
        JSONObject bs= new JSONObject();
        JSONObject br = dao.queryJSONObjectBySql(BookCommutils.bookRuleStr(param));
        JSONObject req = new JSONObject();
        JSONObject reset = JSONObject.parseObject(br.getString("ruleSet"));
        String ruleId = param.getString("ruleId") ;
        List<String> set = new ArrayList<>();
        param.put("type","chapterContext");
        set.add("chapterContext");
        JSONObject cond = new JSONObject();
        cond.put("key",chapterId);
        cond.put("num",set);
        req.put("ruleSet",reset);
        req.put("cond",cond);
        req.put("thread",1);
        req.put("param",param);//附加参数
        req.put("url",param.getString("chapterUrl"));

        jxRulePage(req);
        //  RuleJXData.RuleJXDataPage(req);
        bs = (JSONObject) EhcacheUtil.getInstance().get("bookEhcache",chapterId);
        return bs;
    }


    /**
     * 网站初始化
     * 必填 ruleId 取值链接规则
     * 由于数据量大 范围需区间处理
     * @param param
     * @return
     */
    @Override
    public JSONObject initBook(JSONObject param) {
        JSONObject bs= new JSONObject();
        JSONObject br = dao.queryJSONObjectBySql(BookCommutils.bookRuleStr(param));

        param.put("type","initData");
        JSONObject reset = JSONObject.parseObject(br.getString("ruleSet"));
        int start = param.getInteger("start");
        int end = param.getInteger("end");
        ExecutorService svr = Executors.newCachedThreadPool();
        ExecutorService exec = Executors.newFixedThreadPool(1);//工头
        svr.submit(new saveRedisThead("initData"));
        for(int i=start;i<=end;i++){
            JSONObject req = new JSONObject();
            String  url = param.getString("url").replace("*",String.valueOf(i));
            List<String> set = new ArrayList<>();
            String bookId = BookCommutils.MD5(url);
            set.add("bookChapterList");
            JSONObject cond = new JSONObject();
            cond.put("key",bookId);
            cond.put("num",set);
            req.put("ruleSet",reset);
            req.put("cond",cond);
            req.put("thread",1);
            req.put("param",param);//附加参数
            req.put("url",url);
            exec.submit(new JXPageRuleThread(req,"1"));
        }


        return null;
    }



    @SneakyThrows
    @Override
    public String downloadFile(JSONObject param) {
        String bookId = param.getString("bookId");
        //获取当前章节缓存
        JSONObject ns =   (JSONObject) EhcacheUtil.getInstance().get("bookEhcache",bookId);
        JSONArray chapterInfo = ns.getJSONArray("chapterInfo");

        JSONObject br = dao.queryJSONObjectBySql(BookCommutils.bookRuleStr(param));
        JSONObject req = new JSONObject();
        JSONObject reset = JSONObject.parseObject(br.getString("ruleSet"));
        Long a= System.currentTimeMillis();

        ExecutorService exec = Executors.newFixedThreadPool(20);// 线程数

        for (int i = 0; i < chapterInfo.size(); i++) {
            JSONObject p = chapterInfo.getJSONObject(i);
            List<String> set = new ArrayList<>();
            set.add("downFile");
            JSONObject cond = new JSONObject();
            cond.put("key","downFile");
            cond.put("num",set);
            req.put("ruleSet",reset);
            req.put("cond",cond);
            //req.put("thread",10);
            req.put("param",p);//附加参数
            req.put("url",p.getString("chapterUrl"));
            // jxRulePage(req);
            exec.submit(new JXPageRuleThread(req,"1"));
        }
        exec.shutdown();
        exec.awaitTermination(1, TimeUnit.HOURS);

        //缓存取数据
        JSONArray jsonArray= JSONArray.parseArray(JSONObject.toJSONString(EhcacheUtil.getInstance().get("bookEhcache","downFile")));
        //移除缓存
        //  EhcacheUtil.getInstance().remove("bookEhcache", "downFile");
        jsonArray.sort(Comparator.comparing(obj -> ((JSONObject) obj).getInteger("num")));
        String sysPath = System.getProperty("user.dir");
        String tempPath = "/temp/bookDowntemmp/";
        System.out.println("系统路径"+System.getProperty("user.dir"));

        File file = new File(sysPath+tempPath);
        if(!file.exists()){
            file.mkdirs();
        }
        String titleName = param.getString("bookName")+".txt";
        File writename = new File(sysPath+tempPath+titleName);
        writename.createNewFile();
        BufferedWriter out = new BufferedWriter(new FileWriter(writename));
        StringBuffer str = new StringBuffer();
        for (int i = 0; i < jsonArray.size(); i++) {
            str.setLength(0);
            JSONObject da = jsonArray.getJSONObject(i);
            str.append(da.getString("chapterName"));
            out.write(str.toString());
            out.write("\r\n");
            //多增加 一空行
            out.write("\r\n");
            str.setLength(0);
            str.append(da.getString("context").replaceAll("    ","\r"));
            out.write(str.toString());
            out.write("\r\n");
            //多增加 一空行
            out.write("\r\n");
        }
        out.close();
        Long b = System.currentTimeMillis();
        System.out.println("耗时长:"+(b-a)/1000);
        return sysPath+tempPath+titleName;
    }


    /**
     * 通用解析处理
     * @ type：0 单个解析 1 指定顺序 3 单书下载
     * 自定义规则解析 使用 List<String> 解析顺序
     * 多线程解析 加速效率
     */
    public JSONObject jxRulePage(JSONObject param) {
        int thread  = 1;
        if (param.containsKey("thread"))
            thread = param.getInteger("thread");
        try {
            final long start = System.currentTimeMillis();
            ExecutorService exec = Executors.newFixedThreadPool(thread);// 线程数
            exec.submit(new JXPageRuleThread(param,"1"));

            exec.shutdown();
            exec.awaitTermination(1, TimeUnit.HOURS);
            final long end = System.currentTimeMillis();
            System.out.println("线程执行时间："+(end-start)/1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return null;
    }

}
